/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.brooklyn.ambari.server;
import java.net.URI;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.location.MachineLocation;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.core.annotation.EffectorParam;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.location.Locations;
import org.apache.brooklyn.core.location.Machines;
import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
import org.apache.brooklyn.enricher.stock.Enrichers;
import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
import org.apache.brooklyn.feed.http.HttpFeed;
import org.apache.brooklyn.feed.http.HttpPollConfig;
import org.apache.brooklyn.feed.http.HttpValueFunctions;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.task.DynamicTasks;
import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.executor.HttpExecutorFactory;
import org.apache.brooklyn.util.guava.Functionals;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.http.HttpTool;
import org.apache.brooklyn.util.text.Identifiers;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.net.HostAndPort;
import com.google.common.net.HttpHeaders;
import com.google.gson.JsonElement;
import com.jayway.jsonpath.JsonPath;
import io.brooklyn.ambari.AmbariCluster;
import io.brooklyn.ambari.rest.AmbariApiException;
import io.brooklyn.ambari.rest.AmbariRequestInterceptor;
import io.brooklyn.ambari.rest.AmbariRestClient;
import io.brooklyn.ambari.rest.RequestCheckRunnable;
import io.brooklyn.ambari.rest.domain.AlertTargets;
import io.brooklyn.ambari.rest.domain.HostGroup;
import io.brooklyn.ambari.rest.domain.RecommendationWrapper;
import io.brooklyn.ambari.rest.domain.RecommendationWrappers;
import io.brooklyn.ambari.rest.domain.Request;
import io.brooklyn.ambari.rest.endpoint.AlertGroupEndpoint;
import io.brooklyn.ambari.rest.endpoint.AlertTargetEndpoint;
import io.brooklyn.ambari.rest.endpoint.BlueprintEndpoint;
import io.brooklyn.ambari.rest.endpoint.ClusterEndpoint;
import io.brooklyn.ambari.rest.endpoint.ConfigurationEnpoint;
import io.brooklyn.ambari.rest.endpoint.HostEndpoint;
import io.brooklyn.ambari.rest.endpoint.ServiceEndpoint;
import io.brooklyn.ambari.rest.endpoint.StackEndpoint;
import io.brooklyn.ambari.rest.endpoint.UsersEndpoint;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Client;
public class AmbariServerImpl extends SoftwareProcessImpl implements AmbariServer {
public static final Logger LOG = LoggerFactory.getLogger(AmbariServerImpl.class);
public static final Map<String, String> BASE_BLUEPRINTS = ImmutableMap.of("stack_name", "HDP", "stack_version", "2.2");
public static final List<? extends Map<?, ?>> CONFIGURATIONS = ImmutableList.of(ImmutableMap.of("nagios-env", ImmutableMap.of("nagios_contact", "admin@localhost")));
private volatile HttpFeed serviceUpHttpFeed;
private volatile HttpFeed hostsHttpFeed;
private volatile HttpFeed clusterHttpFeed;
private String ambariUri;
private RestAdapter restAdapter;
private Client ambariRestClient;
private UsernamePasswordCredentials usernamePasswordCredentials;
private static final String USERNAME = "admin";
private static final String INITIAL_PASSWORD = "admin";
private Map<String, Integer> registeredAlertNotifications;
@Override
public Class<AmbariServerDriver> getDriverInterface() {
return AmbariServerDriver.class;
}
@Override
protected void connectSensors() {
super.connectSensors();
connectServiceUpIsRunning();
Collection<? extends Location> locations = Locations.getLocationsCheckingAncestors(getLocations(), this);
Maybe<MachineLocation> location = Machines.findUniqueElement(locations, MachineLocation.class);
if (location.isPresent() && location.get().hasExtension(HttpExecutorFactory.class)) {
ambariRestClient = AmbariRestClient.builder()
.httpExecutorFactory(location.get().getExtension(HttpExecutorFactory.class))
.httpExecutorProps(location.get().getAllConfig(true))
.build();
} else {
ambariRestClient = new AmbariRestClient();
}
HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(this, getAttribute(HTTP_PORT));
ambariUri = String.format("http://%s:%d", hp.getHostText(), hp.getPort());
setAttribute(Attributes.MAIN_URI, URI.create(ambariUri));
sensors().set(AmbariServer.USERNAME, USERNAME);
usernamePasswordCredentials = new UsernamePasswordCredentials(
USERNAME,
getAttribute(AmbariServer.PASSWORD) == null ? INITIAL_PASSWORD : getAttribute(AmbariServer.PASSWORD));
restAdapter = new RestAdapter.Builder()
.setEndpoint(ambariUri)
.setClient(ambariRestClient)
.setRequestInterceptor(new AmbariRequestInterceptor(usernamePasswordCredentials))
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
serviceUpHttpFeed = HttpFeed.builder()
.entity(this)
.period(500, TimeUnit.MILLISECONDS)
.baseUri(ambariUri)
.poll(new HttpPollConfig<Boolean>(URL_REACHABLE)
.onSuccess(HttpValueFunctions.responseCodeEquals(200))
.onFailureOrException(Functions.constant(false)))
.build();
enrichers().add(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
.from(URL_REACHABLE)
.computing(Functionals.ifNotEquals(true).value("URL not reachable"))
.build());
connectAuthenticatedSensors();
}
Function<JsonElement, List<String>> getHosts() {
Function<JsonElement, List<String>> path = new Function<JsonElement, List<String>>() {
@Nullable
@Override
public List<String> apply(@Nullable JsonElement jsonElement) {
String jsonString = jsonElement.toString();
return JsonPath.read(jsonString, "$.items[*].Hosts.host_name");
}
};
return path;
}
Function<JsonElement, String> getRequestState() {
Function<JsonElement, String> path = new Function<JsonElement, String>() {
@Nullable
@Override
public String apply(@Nullable JsonElement jsonElement) {
String jsonString = jsonElement.toString();
return JsonPath.read(jsonString, "$.Requests.request_status");
}
};
return path;
}
@Override
public void disconnectSensors() {
super.disconnectSensors();
disconnectServiceUpIsRunning();
if (serviceUpHttpFeed != null) serviceUpHttpFeed.stop();
disconnectAuthenticatedSensors();
}
@Override
public RecommendationWrappers getRecommendations(String stackName, String stackVersion, List<String> hosts, List<String> services) {
waitForServiceUp();
return restAdapter.create(StackEndpoint.class).getRecommendations(stackName, stackVersion, ImmutableMap.builder()
.put("hosts", hosts)
.put("services", services)
.put("recommend", "host_groups")
.build());
}
@Override
public Request deployCluster(String clusterName, String blueprintName, RecommendationWrapper recommendationWrapper, Map config) throws AmbariApiException {
Preconditions.checkNotNull(recommendationWrapper);
Preconditions.checkNotNull(recommendationWrapper.getStack());
Preconditions.checkNotNull(recommendationWrapper.getRecommendation());
Preconditions.checkNotNull(recommendationWrapper.getRecommendation().getBlueprint());
Preconditions.checkNotNull(recommendationWrapper.getRecommendation().getBindings());
try {
restAdapter.create(BlueprintEndpoint.class).createBlueprint(blueprintName, ImmutableMap.builder()
.put("host_groups", recommendationWrapper.getRecommendation().getBlueprint().getHostGroups())
.put("configurations", getConfigurations(config))
.put("Blueprints", recommendationWrapper.getStack())
.build());
List<HostGroup> confHostGroupsList = recommendationWrapper.getRecommendation().getBindings().getHostGroups();
List<HostGroup> nonZeroHostGroupList = new LinkedList<>();
for(HostGroup hostGroupN:confHostGroupsList) {
if (hostGroupN.getHosts().size() > 0) {
nonZeroHostGroupList.add(hostGroupN);
}
}
return restAdapter.create(ClusterEndpoint.class).createCluster(clusterName, ImmutableMap.builder()
.put("blueprint", blueprintName)
.put("default_password", usernamePasswordCredentials.getPassword())
.put("host_groups", nonZeroHostGroupList)
.build());
} catch (RetrofitError retrofitError) {
throw new AmbariApiException(retrofitError);
}
}
@Override
public void addHostToCluster(@EffectorParam(name = "Cluster name") String cluster,
@EffectorParam(name = "Host FQDN") String hostName) {
waitForServiceUp();
restAdapter.create(HostEndpoint.class).addHost(cluster, hostName);
}
@Override
public void createCluster(@EffectorParam(name = "Cluster Name") String clusterName,
@EffectorParam(name = "Blueprint Name") String blueprintName,
@EffectorParam(name = "Stack Name") String stackName,
@EffectorParam(name = "Stack version") String stackVersion,
@EffectorParam(name = "Hosts", description = "List of FQDNs to add to cluster") List<String> hosts,
@EffectorParam(name = "Services", description = "List of services to install on cluster") List<String> services,
@EffectorParam(name = "Configurations", description = "Map of configurations to apply to blueprint") Map<String, Map> config) {
final RecommendationWrappers recommendationWrappers = getRecommendations(stackName, stackVersion, hosts, services);
deployCluster(clusterName, blueprintName, recommendationWrappers.getRecommendationWrappers().size() > 0 ? recommendationWrappers.getRecommendationWrappers().get(0) : null, config);
}
@Override
public void updateStackRepository(@EffectorParam(name = "Stack Name") String stackName, @EffectorParam(name = "Stack Version") String stackVersion, @EffectorParam(name = "Operating System") String os, @EffectorParam(name = "Repository Name") String repoName, @EffectorParam(name = "Repository URL") String url) {
waitForServiceUp();
restAdapter.create(StackEndpoint.class)
.updateStackRepository(stackName, stackVersion, os, repoName, ImmutableMap.builder()
.put("Repositories", ImmutableMap.builder()
.put("base_url", url)
.put("verify_base_url", true)
.build())
.build());
}
@Override
public void addServiceToCluster(@EffectorParam(name = "cluster", description = "Cluster name") final String cluster,
@EffectorParam(name = "service", description = "Service name") final String service,
@EffectorParam(name = "mappings", description = "Mappings of component to host") Map<String, String> mappings,
@EffectorParam(name = "configuration", description = "Services Configuration", nullable = true, defaultValue = EffectorParam.MAGIC_STRING_MEANING_NULL) Map<String, Map<Object, Object>> configuration) {
waitForServiceUp();
final ServiceEndpoint serviceEndpoint = restAdapter.create(ServiceEndpoint.class);
final HostEndpoint hostEndpoint = restAdapter.create(HostEndpoint.class);
// Step 1 - Add the service to the cluster
serviceEndpoint.addService(cluster, service);
// Step 2 - Add Components to the service
// Step 3 - Create host components
for (Map.Entry<String, String> mapping : mappings.entrySet()) {
serviceEndpoint.createComponent(cluster, service, mapping.getKey());
hostEndpoint.createHostComponent(cluster, mapping.getValue(), mapping.getKey());
}
// Step 4 - Create configuration, if needed
if (configuration != null) {
for (Map.Entry<String, Map<Object, Object>> entry : configuration.entrySet()) {
createServiceConfiguration(cluster, entry.getKey(), entry.getValue());
}
}
final Task installationTask = Tasks.builder()
.name(String.format("Install %s service", service))
.description(String.format("Install %s service on specified hosts through Ambari REST API", service))
.body(new Runnable() {
@Override
public void run() {
// Step 5 - Install the service
final Request request = serviceEndpoint.updateService(cluster, service, ImmutableMap.builder()
.put("RequestInfo", ImmutableMap.builder()
.put("context", String.format("Install %s service", service))
.build())
.put("ServiceInfo", ImmutableMap.builder()
.put("state", "INSTALLED")
.build())
.build());
RequestCheckRunnable.check(request)
.headers(ImmutableMap.of(HttpHeaders.AUTHORIZATION, HttpTool.toBasicAuthorizationValue(usernamePasswordCredentials)))
.errorMessage(String.format("Error during installation of service \"%s\". Please check the Ambari console for more details: %s", service, ambariUri))
.build()
.run();
}
}).build();
final Task startTask = Tasks.builder()
.name(String.format("Start %s service", service))
.description(String.format("Start %s service on specified hosts through Ambari REST API", service))
.body(new Runnable() {
@Override
public void run() {
// Step 6 - Start the service
startService(cluster, service);
}
}).build();
// Queue the "Installation" subtask and wait for its completion. If something goes wrong during execution, an
// exception will be thrown which will stop the effector and prevent the "start" subtask to run.
DynamicTasks.queue(installationTask);
// Queue the "Start" subtask. At this point, everything went fine. If something goes wrong during execution, an
// exception will be thrown which will stop the effector.
DynamicTasks.queue(startTask);
}
@Override
public void createServiceConfiguration(@EffectorParam(name = "Cluster name") String cluster,
@EffectorParam(name = "Component configuration key") String configurationKey,
@EffectorParam(name = "Component configuration") Map<Object, Object> configuration) {
waitForServiceUp();
restAdapter.create(ConfigurationEnpoint.class).createConfiguration(cluster, ImmutableMap.builder()
.put("Clusters", ImmutableMap.builder()
.put("desired_configs", ImmutableMap.builder()
.put("type", configurationKey)
.put("tag", String.format("version%d", System.currentTimeMillis()))
.put("properties", configuration)
.build())
.build())
.build());
}
@Override
public void addHostsToHostGroup(final String blueprintName, final String hostgroupName, final List<String> hosts, final String cluster) {
Iterable<Map> hostGroupMapping = Iterables.transform(hosts, fqdnsToMaps(blueprintName, hostgroupName));
LOG.info("hosts " + hostGroupMapping.iterator().hasNext());
HostEndpoint hostEndpoint = restAdapter.create(HostEndpoint.class);
Request request = hostEndpoint.addHosts(
cluster,
Lists.newArrayList(hostGroupMapping));
RequestCheckRunnable.check(request)
.headers(ImmutableMap.of(HttpHeaders.AUTHORIZATION, HttpTool.toBasicAuthorizationValue(usernamePasswordCredentials)))
.timeout(Duration.ONE_HOUR)
.errorMessage(String.format("Error during adding %s to %s", hosts, hostgroupName))
.build()
.run();
}
private Function<String, Map> fqdnsToMaps(final String blueprintName, final String hostgroupName) {
return new Function<String, Map>() {
@Nullable
@Override
public Map apply(@Nullable String fqdn) {
return ImmutableMap.of("blueprint", blueprintName,
"host_group", hostgroupName,
"host_name", fqdn);
}
};
}
@Override
public void addAlertNotification(String name, String description, Boolean global, String notificationType,
List<String> alertStates, List<String> ambariDispatchRecipients,
String mailSmtpHost, Integer mailSmtpPort, String mailSmtpFrom, Boolean mailSmtpAuth) {
mailSmtpHost = mailSmtpHost.equals("default") ? (String) ((Map) getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).get("default_properties")).get("mail.smtp.host") : mailSmtpHost;
mailSmtpPort = mailSmtpPort.equals("587") ? (Integer) ((Map) getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).get("default_properties")).get("mail.smtp.port") : mailSmtpPort;
mailSmtpFrom = mailSmtpFrom.equals("default") ? (String) ((Map) getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).get("default_properties")).get("mail.smtp.from") : mailSmtpFrom;
Map<String, Object> ambariAlertNotifications = ImmutableMap.<String, Object>builder()
.put("name", name)
.put("description", description)
.put("global", global)
.put("notification_type", notificationType)
.put("alert_states", alertStates)
.put("properties", ImmutableMap.of(
"ambari.dispatch.recipients", ambariDispatchRecipients,
"mail.smtp.host", mailSmtpHost,
"mail.smtp.port", mailSmtpPort,
"mail.smtp.from", mailSmtpFrom,
"mail.smtp.auth", mailSmtpAuth
))
.build();
createAlertNotification(ambariAlertNotifications);
}
protected void createAlertNotification(){
Map<String, Object> ambariAlertNotifications = MutableMap.of();
for (Map.Entry config: getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).entrySet()) {
Object value = (config.getValue() instanceof Map && !((String) config.getKey()).contains("properties")) ?
((Map) config.getValue()).keySet().toArray()[0] : config.getValue();
ambariAlertNotifications.put((String) config.getKey(), value);
}
Map<String, Object> mergedPropertiesConfig = MutableMap.of();
mergedPropertiesConfig.putAll((Map<String, Object>) getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).get("default_properties"));
if (ambariAlertNotifications.containsKey("properties")) {
mergedPropertiesConfig.putAll((Map<String, Object>) ambariAlertNotifications.get("properties"));
}
ambariAlertNotifications.put("properties", mergedPropertiesConfig);
ambariAlertNotifications.remove("default_properties");
createAlertNotification(ambariAlertNotifications);
}
protected void createAlertNotification(Map<String, Object> ambariAlertNotifications) {
ImmutableMap<String, Map<String, Object>> alertTargetRequest = ImmutableMap.of("AlertTarget", ambariAlertNotifications);
restAdapter.create(AlertTargetEndpoint.class).createAlertNotification(alertTargetRequest);
registeredAlertNotifications = listAlertTargets();
}
@Override
public void editAlertNotification(String name, String description, Boolean global, String notificationType,
List<String> alertStates, List<String> ambariDispatchRecipients,
String mailSmtpHost, Integer mailSmtpPort, String mailSmtpFrom, Boolean mailSmtpAuth) {
registeredAlertNotifications = listAlertTargets();
mailSmtpHost = mailSmtpHost.equals("default") ? (String) ((Map) getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).get("default_properties")).get("mail.smtp.host") : mailSmtpHost;
mailSmtpPort = mailSmtpPort.equals("587") ? (Integer) ((Map) getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).get("default_properties")).get("mail.smtp.port") : mailSmtpPort;
mailSmtpFrom = mailSmtpFrom.equals("default") ? (String) ((Map) getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).get("default_properties")).get("mail.smtp.from") : mailSmtpFrom;
ImmutableMap<String, Object> alertTargetRequest = ImmutableMap.<String, Object>builder()
.put("name", name)
.put("description", description)
.put("global", global)
.put("notification_type", notificationType)
.put("alert_states", alertStates)
.put("properties", ImmutableMap.of(
"ambari.dispatch.recipients", ambariDispatchRecipients,
"mail.smtp.host", mailSmtpHost,
"mail.smtp.port", mailSmtpPort,
"mail.smtp.from", mailSmtpFrom,
"mail.smtp.auth", mailSmtpAuth
))
.build();
if (!registeredAlertNotifications.containsKey(name)) {
throw new UnsupportedOperationException(String.valueOf(Strings.format("Alert with name %s doesn't exist and cannot be updated.", name)));
}
updateAlertTarget(registeredAlertNotifications.get(name), alertTargetRequest);
}
protected Map<String, Integer> listAlertTargets() {
AlertTargets alertTargets = restAdapter.create(AlertTargetEndpoint.class).listAlertNotifications();
Map<String, Integer> result = MutableMap.of();
for (Map<String, Object> item: alertTargets.getItems()) {
result.put((String) ((Map) item.get("AlertTarget")).get("name"), ((Double) ((Map) item.get("AlertTarget")).get("id")).intValue());
}
return result;
}
protected void updateAlertTarget(Integer targetId, Map<String, Object> ambariAlertNotifications) {
ImmutableMap<String, Map<String, Object>> alertTargetRequest = ImmutableMap.of("AlertTarget", ambariAlertNotifications);
restAdapter.create(AlertTargetEndpoint.class).editAlertNotification(targetId, alertTargetRequest);
}
@Override
public void deleteAlertNotification(String name) {
if (registeredAlertNotifications == null) {
registeredAlertNotifications = listAlertTargets();
}
if (!registeredAlertNotifications.containsKey(name)) {
throw new UnsupportedOperationException(String.valueOf(Strings.format("Alert with name %s doesn't exist and cannot be deleted.", name)));
}
restAdapter.create(AlertTargetEndpoint.class).deleteAlertNotification(registeredAlertNotifications.get(name));
}
@Override
public void addAlertGroup(@EffectorParam(name = "Name") String name,
@EffectorParam(name = "Definitions") List<Integer> definitions) {
ImmutableMap<String, ImmutableMap<Object, Object>> alertGroupRequest = ImmutableMap.of("AlertGroup", ImmutableMap.builder()
.put("name", name)
.put("definitions", definitions)
.build());
restAdapter.create(AlertGroupEndpoint.class).createAlertGroup(getConfig(AmbariCluster.CLUSTER_NAME), alertGroupRequest);
}
@Override
public void startService(@EffectorParam(name = "Cluster name") String cluster,
@EffectorParam(name = "Service name") final String service) {
waitForServiceUp();
final Request request = restAdapter.create(ServiceEndpoint.class).updateService(cluster, service, ImmutableMap.builder()
.put("RequestInfo", ImmutableMap.builder()
.put("context", String.format("Start %s service", service))
.build())
.put("ServiceInfo", ImmutableMap.builder()
.put("state", "STARTED")
.build())
.build());
RequestCheckRunnable.check(request)
.headers(ImmutableMap.of(HttpHeaders.AUTHORIZATION, HttpTool.toBasicAuthorizationValue(usernamePasswordCredentials)))
.errorMessage(String.format("Error during the start of service \"%s\". Please check the Ambari console for more details: %s", service, ambariUri))
.build()
.run();
}
@Override
public boolean agentOnServer() {
Iterable<AmbariCluster> ambariClusters = Iterables.filter(Entities.ancestors(this), AmbariCluster.class);
for (Entity parent : ambariClusters) {
return !parent.getConfig(AmbariCluster.SERVER_COMPONENTS).isEmpty();
}
return false;
}
private List<? extends Map<?, ?>> getConfigurations(Map<String, Map> config) {
ImmutableList.Builder<Map<?, ?>> builder = ImmutableList.<Map<?, ?>>builder();
if (config != null) {
for (Map.Entry<String, Map> stringMapEntry : config.entrySet()) {
builder.add(
ImmutableMap.of(
stringMapEntry.getKey(),
ImmutableMap.<String, Map>of(
"properties",
stringMapEntry.getValue())));
}
}
return builder.build();
}
@Override
public String getFqdn() {
return getAttribute(FQDN);
}
@Override
public void setFqdn(String fqdn) {
setAttribute(FQDN, fqdn);
}
public void setRestAdapter(RestAdapter restAdapter) {
this.restAdapter = restAdapter;
}
@Override
public void postStart() {
super.postStart();
generateAndUpdatePassword();
if (getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS)!= null && !getConfig(AmbariCluster.AMBARI_ALERT_NOTIFICATIONS).isEmpty()) {
createAlertNotification();
}
registeredAlertNotifications = listAlertTargets();
}
/**
* Need to wait server to start before resetting the password.
*/
protected void generateAndUpdatePassword() {
String password = getAttribute(AmbariServer.PASSWORD);
if (password == null) {
password = getConfig(AmbariServer.PASSWORD);
if (password == null) {
password = Identifiers.makeRandomId(10);
}
usernamePasswordCredentials = new UsernamePasswordCredentials(USERNAME, password);
ImmutableMap<String, ImmutableMap<String, String>> userRequest = ImmutableMap.of("Users", ImmutableMap.of(
"user_name", USERNAME,
"old_password", INITIAL_PASSWORD,
"password", usernamePasswordCredentials.getPassword()
));
waitForServiceUp();
restAdapter.create(UsersEndpoint.class).updateUser(userRequest);
restAdapter = new RestAdapter.Builder()
.setEndpoint(ambariUri)
.setClient(ambariRestClient)
.setRequestInterceptor(new AmbariRequestInterceptor(usernamePasswordCredentials))
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
disconnectAuthenticatedSensors();
connectAuthenticatedSensors();
sensors().set(AmbariServer.PASSWORD, password);
}
}
private void connectAuthenticatedSensors() {
hostsHttpFeed = HttpFeed.builder()
.entity(this)
.period(1000, TimeUnit.MILLISECONDS)
.baseUri(String.format("%s/api/v1/hosts", ambariUri))
.credentials(usernamePasswordCredentials.getUserName(), usernamePasswordCredentials.getPassword())
.header(HttpHeaders.AUTHORIZATION, HttpTool.toBasicAuthorizationValue(usernamePasswordCredentials))
.poll(new HttpPollConfig<List<String>>(REGISTERED_HOSTS)
.onSuccess(Functionals.chain(HttpValueFunctions.jsonContents(), getHosts()))
.onFailureOrException(Functions.<List<String>>constant(ImmutableList.<String>of())))
.build();
clusterHttpFeed = HttpFeed.builder()
.entity(this)
.period(1000, TimeUnit.MILLISECONDS)
.baseUri(String.format("%s/api/v1/clusters/%s/requests/%d",
ambariUri,
getConfig(AmbariCluster.CLUSTER_NAME),
1))
.credentials(usernamePasswordCredentials.getUserName(), usernamePasswordCredentials.getPassword())
.header(HttpHeaders.AUTHORIZATION, HttpTool.toBasicAuthorizationValue(usernamePasswordCredentials))
.poll(new HttpPollConfig<String>(CLUSTER_STATE)
.onSuccess(Functionals.chain(HttpValueFunctions.jsonContents(), getRequestState()))
.onFailureOrException(Functions.<String>constant(null)))
.build();
}
private void disconnectAuthenticatedSensors() {
if (hostsHttpFeed != null) hostsHttpFeed.stop();
if (clusterHttpFeed != null) clusterHttpFeed.stop();
}
}